package Domain.MySqlAccessors;

import Persistance.MySqlUtilityManagment;
import Persistance.PrintfFormat;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Random;

import Domain.Movie;
import Domain.Actor;
import Domain.Genre;
import Domain.SearchMovieMethods;
import BusinessLogic.Exceptions.DataAlreadyExistException;

public class MySqlMovieProxy extends MySqlProxy<Movie> {

    private MySqlMovieActorProxy m_movieActor;
    private MySqlMovieGenreProxy m_movieGenre;
    private MySqlActorProxy m_actors;
    private MySqlGenreProxy m_genres;

    public MySqlMovieProxy(MySqlUtilityManagment sql) {
        super(sql);
        TABLE_NAME = "movies";
        KEY_COLUMN_NAME = "name='%s'";
        ALL_COLUMN_NAMES = "name, director, year, length, country";

        m_movieActor = new MySqlMovieActorProxy(sql);
        m_movieGenre = new MySqlMovieGenreProxy(sql);
        m_actors = new MySqlActorProxy(sql);
        m_genres = new MySqlGenreProxy(sql);
    }

    public void addRecord(Movie m) throws DataAlreadyExistException {
        super.addRecord(m);        

        for (Actor actor : m.getActors())
            m_movieActor.addRecord(new MovieActor(m.getName(),actor.getId()));
        for (Genre genre : m.getGenres())
            m_movieGenre.addRecord(new MovieGenre(m.getName(),genre.getId()));
    }

    public Movie getRecord(String key) {
        Movie m = super.getRecord(key);

        if (m != null) {
            for (Actor a: m_movieActor.actorsOf(m.getName()))
                m.addActor(a);

            for (Genre g: m_movieGenre.genresOf(m.getName()))
                m.addGenre(g);
        }

        return m;
    }

    public Movie toRecordType(ResultSet rs) throws SQLException {
        String name = (String) rs.getObject("name");
        String director = (String) rs.getObject("director");
        String year = (String) rs.getObject("year");
        int length = ((Long) rs.getObject("length")).intValue();
        String country = (String) rs.getObject("country");
        return new Movie(name,director,year,length,country);
    }

    public String toValues(Movie m) {
        Object[] values = {m.getName(),m.getDirector(),m.getYear(),m.getLength(),m.getCountry()};
        return new PrintfFormat("'%s','%s','%s',%d,'%s'").sprintf(values);
    }

    public String[] searchMovies(String keyword, SearchMovieMethods method, int start, int amount) {
        return searchMovies(keyword, method, start, amount, null);
    }

    public String[] searchMovies(String keyword, SearchMovieMethods method, int start, int amount, String startWith) {
        logger.debug("Searching movie by "+method+ ", keyword="+keyword);
        String filterPrefix = "";
        if (startWith!=null && !startWith.equals(""))
            filterPrefix = "name LIKE '"+startWith+"%'";
        String filter;

        switch(method) {
            case ACTOR:
                if (startWith!=null && !startWith.equals(""))
                    filterPrefix = "movie LIKE '"+startWith+"%'";
                filter = composeLogicalExpression(filterPrefix,"actorId="+keyword);
                return m_sql.searchData("movieActors","movie",filter,start,amount);
            case GENRE:
                if (startWith!=null && !startWith.equals(""))
                    filterPrefix = "movie LIKE '"+startWith+"%'";
                filter = composeLogicalExpression(filterPrefix,"genre="+keyword);
                return m_sql.searchData("movieGenres","movie",filter,start,amount);
            case UNRECOMMENDED:
                filter = composeLogicalExpression(filterPrefix,"name not in(select moviename from recommendations where username=\""+ keyword +"\")");
                return m_sql.searchData(TABLE_NAME,"name",filter,start,amount);
            case ALL:
                return m_sql.searchData(TABLE_NAME,"name",filterPrefix,start,amount);
            default:
                filter = composeLogicalExpression(filterPrefix,method.getName()+"='"+keyword+"'");
                return m_sql.searchData(TABLE_NAME,"name",filter,start,amount);
        }
    }

    private String composeLogicalExpression(String logical1,String logical2) {
        if (logical1 == null || logical1.equals(""))
            return logical2;
        if (logical2 == null || logical2.equals(""))
            return logical1;
        return logical1+" AND "+logical2;
    }

    public String[] searchMovies(String keyword, String filter, int start, int amount) {
		return m_sql.searchData("movies","name",filter,start,amount);
	}

    /**
     * Accessors to the movieActors table.
     */
    class MySqlMovieActorProxy extends MySqlProxy<MovieActor>{

        public MySqlMovieActorProxy(MySqlUtilityManagment sql) {
            super(sql);
            TABLE_NAME = "movieActors";
            KEY_COLUMN_NAME = "movie='%s' AND actorId=%d";
            ALL_COLUMN_NAMES = "movie, actorId";
        }

        public MovieActor toRecordType(ResultSet rs) throws SQLException{
            String movie = (String) rs.getObject("movie");
            long actor = (Long)rs.getObject("actorId");
            return new MovieActor(movie,actor);                       
        }

        public String toValues(MovieActor ma) {
            Object[] values = {ma.movie,ma.actor};
            return new PrintfFormat("'%s',%d").sprintf(values);
        }

        public Collection<Actor> actorsOf(String movie) {
            return m_actors.searchRecords("id IN (SELECT actorId FROM movieActors WHERE movie='"+movie+"')");
        }
    }

    /**
     * Accessors to the MovieGenres table.
     */
    class MySqlMovieGenreProxy extends MySqlProxy<MovieGenre> {

        public MySqlMovieGenreProxy(MySqlUtilityManagment sql) {
            super(sql);
            TABLE_NAME = "movieGenres";
            KEY_COLUMN_NAME = "movie='%s' AND genre=%s";
            ALL_COLUMN_NAMES = "movie, genre";
        }

        public MovieGenre toRecordType(ResultSet rs) throws SQLException{
            String movie = (String) rs.getObject("movie");
            long genre = (Long) rs.getObject("genre");
            return new MovieGenre(movie,genre);
        }

        public String toValues(MovieGenre mg) {
            Object[] values = {mg.movie,mg.genre};
            return new PrintfFormat("'%s',%d").sprintf(values);
        }

        public Collection<Genre> genresOf(String movie) {
            return m_genres.searchRecords("id IN (SELECT genre FROM movieGenres WHERE movie='"+movie+"')");
        }
    }

    // data structures
    class MovieActor {
        public String movie;
        public long actor;

        public MovieActor(String name, long id) {
            movie = name;
            actor = id;
        }
    }

    class MovieGenre {
        public String movie;
        public long genre;

        public MovieGenre(String name, long id) {
            movie = name;
            genre = id;
        }
    }   
}
